package com.mike.uaa.core;


import cn.hutool.core.util.StrUtil;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;

/**
 * @author z
 */
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {

    private static final long serialVersionUID = 260463504960155271L;

    private final Collection<? extends GrantedAuthority> authorities;

    private boolean authenticated;

    /**
     * 使用提供的颁发机构数组创建令牌。
     *
     * @param authorities 此身份验证对象表示的主体的 GrantedAuthority 集合。
     */
    public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
        if (authorities == null) {
            this.authorities = new HashSet<>();
            return;
        }
        Collection<GrantedAuthority> f = new HashSet<>();
        for (GrantedAuthority authority : authorities) {
            if (authority != null) f.add(authority);
        }
        this.authorities = Collections.unmodifiableCollection(f);

    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public boolean isAuthenticated() {
        return this.authenticated;
    }


    @Override
    public void setAuthenticated(boolean authenticated) {
        this.authenticated = authenticated;
    }


    public String getName() {
        if (getPrincipal() == null) {
            return StrUtil.EMPTY;
        }
        if (getPrincipal() instanceof User) {
            return ((User) getPrincipal()).getUsername();
        }
        return getPrincipal().toString();
    }

    @Override
    public void eraseCredentials() {
        eraseSecret(getCredential());
        eraseSecret(getPrincipal());
    }

    private void eraseSecret(Object secret) {
        if (secret instanceof CredentialsContainer) {
            CredentialsContainer container = (CredentialsContainer) secret;
            container.eraseCredentials();
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractAuthenticationToken)) {
            return false;
        }
        AbstractAuthenticationToken test = (AbstractAuthenticationToken) obj;
        if (!this.authorities.equals(test.authorities)) {
            return false;
        }


        if ((this.getCredential() == null) && (test.getCredential() != null)) {
            return false;
        }
        if ((this.getCredential() != null) && !this.getCredential().equals(test.getCredential())) {
            return false;
        }
        if (this.getPrincipal() == null && test.getPrincipal() != null) {
            return false;
        }
        if (this.getPrincipal() != null && !this.getPrincipal().equals(test.getPrincipal())) {
            return false;
        }
        return this.isAuthenticated() == test.isAuthenticated();
    }


    @Override
    public int hashCode() {
        int code = 31;
        for (GrantedAuthority authority : this.authorities) {
            code ^= authority.hashCode();
        }
        if (this.getPrincipal() != null) {
            code ^= this.getPrincipal().hashCode();
        }
        if (this.getCredential() != null) {
            code ^= this.getCredential().hashCode();
        }

        if (this.isAuthenticated()) {
            code ^= -37;
        }
        return code;
    }


    @Override
    public String toString() {
        return getClass().getSimpleName() + " [" +
                "Principal=" + getPrincipal() + ", " +
                "Credentials=[PROTECTED], " +
                "Authenticated=" + isAuthenticated() + ", " +
                "Granted Authorities=" + this.authorities +
                "]";
    }

}
